package be.kul.osgi.ds.myagent;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.InvalidPropertiesFormatException;
import java.util.Iterator;
import java.util.Vector;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;

import rmi.serverinterface.InitTask;

import be.kul.osgi.ds.comminterface.CommunicationInterface;
import be.kul.osgi.ds.comminterface.MyEvent;
import be.kul.osgi.ds.comminterface.MyEventListener;
import be.kul.osgi.ds.irole.IRole;
import be.kul.osgi.ds.irole.ITask;
import be.kul.osgi.ds.messageservice.MessageObject;
import be.kul.osgi.ds.messageservice.MessageService;
import be.kul.osgi.ds.myagent.message.MessageHandler;
import be.kul.osgi.ds.rmi.RMIConnection;
import be.kul.osgi.ds.xmlstreamservice.XMLStreamService;
import be.kul.osgi.http.fileserver.Server;

public class MyAgent extends Thread implements MyEventListener{
	
	public String name;
	public Vector<IRole> roles;//used vector to easily integrate with JList in GUI
	AgentGui ui;
	public BundleContext context;
	public String bundledata;
	public XMLStreamService XMLStreamservice;
	private CommunicationInterface commservice;
	public Server serverservice;
	private MessageService messageservice;
	public RMIConnection rmi;
	public MessageHandler messagehandler;
	public SyncThread thread;
	
	private int port;
	public Schedule schedule;
	/*
	 * COMPONENT FUNCTIONS 
	 */
	
	//this is executed after all services are loaded
	public void activate(BundleContext context) throws URISyntaxException, IOException{
		System.out.println("Activate in myAgent executed");
		ui = new AgentGui(this);
		bundledata = context.getBundle().getDataFile("").getAbsolutePath();
		System.out.println(bundledata);
		messagehandler = new MessageHandler(this, XMLStreamservice);
		this.context = context;
		this.socket_init(4567, "224.0.0.123");
				
		this.schedule = new Schedule();
		
		//this.inittasks();
		this.thread = new SyncThread(this);
		
	}
	
	
	public MyAgent(){
		String n = System.getProperty("agentname");
		int p = Integer.parseInt(System.getProperty("org.eclipse.equinox.http.jetty.http.port"));
		if (n != null){
			this.name = n;
		} else {
			this.name = "agent 007";
		}
		this.port = p;
		roles = new Vector<IRole>();
	}
	
	public void run() {
		//Display info about this particular thread
		System.out.println("inside run");
		//neverending loop
		while(true)
		{
			try {
				ui.refresh();
				Thread.sleep(5000);
			} catch (Exception e) {
				System.out.println("Thread interrupted " + e.getMessage());
			}
		}
	}
	
	public void messageReceived(MyEvent event) {
		String message = event.mes;
		String sender = event.sender;
		System.out.println("MESSAGE");
		System.out.println(event.mes);
		MessageObject m = this.XMLStreamservice.readClass(event.mes, MessageObject.class);
		
		if ((m.getReceiver().equals(this.name) || m.getReceiver().equals("multi")) && !m.getSender().equals(this.name)) {
			try {
				messagehandler.HandleMessage(message, sender);
			} catch (InvalidPropertiesFormatException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
		
	}

	
	/*
	 * MESSAGING INTERFACE 
	 */
	
	public synchronized void setMessage(MessageService messageservice) {
		System.out.println("Messagecomponent was set. Thank you DS!");
		this.messageservice = messageservice;
	}

	public synchronized void unsetMessage(MessageService messageservice) {
		System.out.println("Messagecomponent was unset. Why did you do this to me?");
		if (this.messageservice == messageservice) {
			this.messageservice = null;
		}
	}
	
	public MessageService getMessageService(){
		return this.messageservice;
	}
	
	/*
	 *  ROLES INTERFACE 
	 */
	
	public synchronized void setRole(IRole roleservice) {
		System.out.println("RoleService was set. Thank you DS!");
		roles.add(roleservice);
		// I know I should not use the service here but just for demonstration
		if (ui != null) {
			ui.refresh();
		}
	}

	// Method will be used by DS to unset the quote service
	public synchronized void unsetRole(IRole roleservice) {
		System.out.println("RoleService was unset. Why did you do this to me?");
		roles.remove(roleservice);
		if (ui != null) {
			ui.refresh();
		}
	}
	
	public Vector<IRole> getRoles(){
		return roles;	
	}
	
	
	/*
	 * SERVER INTERFACE 
	 */
	
	public synchronized void setServer(Server serverservice) {
		System.out.println("Fileserver was set. Thank you DS!");
		this.serverservice = serverservice;
	}

	// Method will be used by DS to unset the quote service
	public synchronized void unsetServer(Server serverservice) {
		System.out.println("Fileserver was unset. Why did you do this to me?");
		if (this.serverservice == serverservice) {
			this.serverservice = null;
		}
	}
		
	/*
	 * COMMUNICATION INTERFACE - UDP in this case
	 */
	
	public synchronized void setComm(CommunicationInterface commservice) {
		System.out.println("Communicationcomponent was set. Thank you DS!");
		this.commservice = commservice;
	}

	// Method will be used by DS to unset the quote service
	public synchronized void unsetComm(CommunicationInterface commservice) {
		System.out.println("Communicationcomponent was unset. Why did you do this to me?");
		if (this.commservice == commservice) {
			this.commservice = null;
		}
	}
	
	/*
	 * RMIConnection
	 */
	
	public void setRMI(RMIConnection rmi){
		System.out.println("RMIcomponent was set. Thank you DS!");
		this.rmi = rmi;	
		
	}
	
	public void unsetRMI(RMIConnection rmi){
		System.out.println("RMIcomponent was unset. Why did you do this to me?");
		if (this.rmi == rmi) {
			this.rmi = null;
		}	
	}
	
	/*
	 * XMLSTREAMSERVICE
	 */
	public void setXMLStreamService(XMLStreamService service){
		System.out.println("Messagecomponent was set. Thank you DS!");
		this.XMLStreamservice = service;		
	}
	
	public void unsetXMLStreamService(XMLStreamService service){
		System.out.println("XMLServicecomponent was unset. Why did you do this to me?");
		if (this.XMLStreamservice == service) {
			this.XMLStreamservice = null;
		}		
	}
	
	public XMLStreamService getXMLStreamService()
	{
		return XMLStreamservice;
	}
	
	//init the socket
	
	public void socket_init(int port, String group)
	{
		getComm().init(port);
		getComm().addToGroup(group);
		//getComm().initserver();
		getComm().receive();
		getComm().addMyEventListener(this);
		//getComm().addMyEventListener(ui);
	}
	
	//getters
	
	public CommunicationInterface getComm(){
		if (commservice != null){
			return commservice;
		}
		return null;
	}

	public String getMesID(){
		String id = this.rmi.getMesID();
		return id;
	}
	
	public int getPort(){
		return this.port;
	}
	
	/*
	 * Given the bundle name, it searches and if found the function returns true
	 * Otherwist it return false.
	 */
	public boolean BundleLookup(String SymName){
		Bundle[] bundles = this.context.getBundles();
		for(int j = 0; j < bundles.length; j++){
			if (SymName.equals(bundles[j].getSymbolicName())){
				return true;
			}
		}
		return false;
	}
	
	/*
	 * Given the bundle name, it searches and gives back the bundle.
	 * Otherwist it return null.
	 */
	public Bundle getBundle(String SymName){
		Bundle[] bundles = this.context.getBundles();
		for(int j = 0; j < bundles.length; j++){
			if (SymName.equals(bundles[j].getSymbolicName())){
				return bundles[j];
			}
		}
		return null;
	}
	
	public IRole getRoleFromName(String role) {
		
		try {
			Collection<ServiceReference<IRole>> roles = this.context.getServiceReferences(IRole.class, null);
			Iterator<ServiceReference<IRole>> i = roles.iterator();
			while(i.hasNext()){
				ServiceReference<IRole> sr = i.next();
				if(sr.getBundle().getSymbolicName().toString().equals(role)){
					System.out.println("Bingo");
					return (IRole)this.context.getService(sr);
				}
			}
			
		} catch (InvalidSyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 

		return null;
	}

	public long getTime() {
		// TODO Auto-generated method stub
		//return this.rmi.getTime();
		return 0;
	}
	
	public void inittasks(){
		ArrayList<InitTask> tasks = this.rmi.inittasks(this.name);
		int size = tasks.size();
		System.out.println("araay size = " + size);
		//do something with that
		for (int i = 0; i < size; i++){
			//System.out.println("ROLES : " +this.roles);
			IRole r = this.roles.get(0);
			ITask t = this.roles.firstElement().makeTask(tasks.get(i).ID, tasks.get(i).duration, tasks.get(i).due, tasks.get(i).x, tasks.get(i).y);
			System.out.println(t);
			Commitment c = new Commitment(t, this);
			try {
				this.schedule.add(c);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(tasks);
	}
	
}